// HEAD SS_GeneralStatistics H
/*==================================================================================================================
                  Copyright (C) 2013 SUMSCOPE L.P.
                  ALL RIGHTS RESERVED
====================================================================================================================
File description:
    Statistics tool
    this class accumulates a set of data and returns their statistics (e.g:
mean, variance, skewness, kurtosis, error estimation, percentile, etc.) based on
the empirical distribution.

====================================================================================================================
...Date      Name                                  Description of Change
28-Apr-2013  James Xu                              Initial version
03-May-2013  James Xu                              Add Correlation and
Covariance 21-May-2013  James Xu                              Add
GetDistributionInfo $HISTORY$
===================================================================================================================*/

#ifndef SS_GENERAL_STATISTICS_HPP
#define SS_GENERAL_STATISTICS_HPP

#include <algorithm>
#include <cmath>
#include <vector>

namespace SS {
struct DistributionInfo {
  double lowRange;
  double upRange;
  int frequency;
  double percentage;
};

struct NormalCurvePoint {
  double xValue;
  double fValue;
};

class GeneralStatistics {
 public:
  GeneralStatistics(void);

  GeneralStatistics(std::vector<double>& samples);

  // Number of samples collected
  std::size_t Samples() const;

  // Adds a datum to the set, possibly with a weight
  void Add(double value, double weight = 1.0);

  // Collected data
  const std::vector<std::pair<double, double> >& Data() const;

  // Sum of data weights
  double WeightSum() const;

  // Returns the mean, defined as
  double Mean() const;

  double Variance() const;

  // Returns the standard deviation 'sigma', defined as the square root of the
  // variance.
  double StandardDeviation() const;

  // Returns the minimum sample value */
  double Min() const;

  // Returns the maximum sample value */
  double Max() const;

  // Return distribution frequency information, normal distribution points
  // distInfoVec       : output
  // normalCurvePoints : output
  // nPoints           : input, the number of points used to interpolated the
  // normal curve
  int GetDistributionInfo(std::vector<DistributionInfo>& distInfoVec,
                          std::vector<NormalCurvePoint>& normalCurvePoints,
                          int nPoints);

 private:
  mutable std::vector<std::pair<double, double> > samples_;
  mutable bool sorted_;
};

// Calculate correlation
double Correlation(const GeneralStatistics& m1, const GeneralStatistics& m2);

// Calculate covariance
double Covariance(const GeneralStatistics& m1, const GeneralStatistics& m2);

inline double GeneralStatistics::StandardDeviation() const {
  return std::sqrt(Variance());
}
inline double GeneralStatistics::Min() const {
  return std::min_element(samples_.begin(), samples_.end())->first;
}

inline double GeneralStatistics::Max() const {
  return std::max_element(samples_.begin(), samples_.end())->first;
}

inline std::size_t GeneralStatistics::Samples() const {
  return samples_.size();
}

inline void GeneralStatistics::Add(double value, double weight) {
  samples_.push_back(std::make_pair(value, weight));
  sorted_ = false;
}

inline const std::vector<std::pair<double, double> >& GeneralStatistics::Data()
    const {
  return samples_;
}

}  // namespace SS

#endif
